using System.Collections.Generic;
using System.IO;
using Asteroid.Content;
using Asteroid.GameObjects;
using GameFramework.Diagnostics;
using GameFramework.Extensions;
using GameFramework.GameObjects;
using GameFramework.Helpers;
using GameFramework.Managers;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;

namespace Asteroid.Screens
{
    /// <summary>
    /// The game screen.
    /// </summary>
    public class GameScreen : Screen
    {
        /// <summary>
        /// The background texture.
        /// </summary>
        private readonly Texture background;

        /// <summary>
        /// The accelerometer text.
        /// </summary>
        private readonly AccelerometerLabel accelerometerLabel;

        /// <summary>
        /// The benckmark object.
        /// </summary>
        private readonly FrameRateLabel benckmark;

        /// <summary>
        /// The button for buying the full version of the game.
        /// </summary>
        private readonly Label buyButton;

        /// <summary>
        /// The spaceship.
        /// </summary>
        private Spaceship spaceship;

        /// <summary>
        /// The list of all the active bullets in the game.
        /// </summary>
        private List<Bullet> bullets;

        /// <summary>
        /// The list of all the active rocks in the game.
        /// </summary>
        private List<Rock> rocks;

        /// <summary>
        /// Initializes a new instance of the <see cref="GameScreen"/> class.
        /// </summary>
        public GameScreen()
        {
            background = new Texture
                         {
                             TextureName = Textures.Space,
                             LayerDepth = 1
                         };

            buyButton = new Label
                        {
                            FontName = Fonts.MenuItem,
                            Color = Color.Yellow,
                            Position = new Vector2(ScreenCenter.X, 50),
                            Text = "Buy",
                            LayerDepth = 0
                        };

            spaceship = new Spaceship
                        {
                            Position = new Vector2(ScreenWidth / 2, ScreenHeight - 50),
                            Scale = new Vector2(0.4f)
                        };

            accelerometerLabel = new AccelerometerLabel
                                {
                                    Position = ScreenCenter,
                                    FontName = Fonts.MenuItem,
                                    Visible = false
                                };

            benckmark = new FrameRateLabel
                        {
                            FontName = Fonts.MenuItem,
                            Position = ScreenCenter,
                            Scale = new Vector2(0.6f),
                            Visible = true
                        };

            bullets = new List<Bullet>();
            rocks = new List<Rock>();

            // Add the static objects into the screen children collection
            Children.Add(background);
            Children.Add(benckmark);
            Children.Add(accelerometerLabel);
        }

        public override void Update()
        {
            base.Update();

            // If the user press the back button we return to the menu screen
            if (IsBackButtonPressed)
            {
                ScreenManager.NavigateBack();
            }

            // Shoot a bullet if we detect a flick gesture
            foreach (var gesture in Game.Input.TouchGestures)
            {
                if (gesture.GestureType == GestureType.Flick)
                {
                    bullets.Add(new Bullet
                                {
                                    Position = spaceship.Position, 
                                    Speed = gesture.Delta / 20
                                });

                    SoundManager.PlaySound(Sounds.Bullet);
                }
            }

            // Add a casual rock sometimes
            if (GameHelper.GetRandomFloat() < 0.02f)
            {
                rocks.Add(new Rock
                          {
                              Position = new Vector2(GameHelper.GetRandomFloat(0, ScreenWidth), -100)
                          });
            }

            // Show the buy button if the game is running in trial mode and show the market place if the user tap it
            if (Game.IsTrialMode)
            {
                buyButton.Update();

                foreach (var touch in Input.TouchCollection)
                {
                    if (buyButton.IsPointOverObject(touch.Position))
                    {
                        Game.ShowMarketplace();
                    }
                }
            }

            // Update all the bullets
            foreach (var bullet in bullets)
            {
                bullet.Update();
            }

            // Update all the rocks
            foreach (var rock in rocks)
            {
                rock.Update();
            }

            // Update the spaceship
            spaceship.Update();

            // Remove all the bullets out of screen
            bullets.RemoveAll(bullet => bullet.PositionY < 0);

            // Remove all the rocks out of screen
            rocks.RemoveAll(rock => rock.PositionY > ScreenHeight);

            // Collision detection
            var spaceshipBoundingbox = spaceship.BoundingBox;

            for (int i = rocks.Count - 1; i >= 0; --i)
            {
                var rockBoundingBox = rocks[i].BoundingBox;

                // Check collision between the spaceship and all the rocks.
                if (spaceshipBoundingbox.Intersects(rockBoundingBox))
                {
                    Game.StartVibration(1000);

                    SoundManager.PlaySound(Sounds.Explosion);
                    SoundManager.PlaySound(Sounds.Explosion);
                    SoundManager.PlaySound(Sounds.Explosion);
                    
                    ScreenManager.NavigateBack();
                    break;
                }

                // Check collision between bullets and rocks
                for (int j = bullets.Count - 1; j >= 0; --j)
                {
                    if (bullets[j].BoundingBox.Intersects(rockBoundingBox))
                    {
                        rocks.RemoveAt(i);
                        bullets.RemoveAt(j);

                        SoundManager.PlaySound(Sounds.Explosion);
                        Game.StartVibration(100);

                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Draw the game screen.
        /// </summary>
        public override void Draw()
        {        
            base.Draw();  

            // Draw all the bullets.
            foreach (var bullet in bullets)
            {
                bullet.Draw();
            }

            // Draw all the rocks.
            foreach (var rock in rocks)
            {
                rock.Draw();
            }

            // Draw the spaceship
            spaceship.Draw();

            // Show the buy button only if the game is running in trial mode 
            if (Game.IsTrialMode)
            {
                buyButton.Draw();
            }
        }

        /// <summary>
        /// Initialize the game screen.
        /// </summary>
        public override void ScreenActivated()
        {
            Game.Input.StartAccelerometer();
            Game.Input.EnabledGestures = GestureType.Flick;

            SoundManager.PlayMusic(Sounds.Music);
        }

        /// <summary>
        /// Screen closing event handler.
        /// </summary>
        public override void ScreenClosing()
        {
            SoundManager.StopMusic();
        }

        /// <summary>
        /// Initialize the game screen from a stream.
        /// </summary>
        /// <param name="reader">The reader</param>
        public override void Read(BinaryReader reader)
        {
            base.Read(reader);

            spaceship = reader.ReadObject<Spaceship>();
            rocks = reader.ReadList<Rock>();
            bullets = reader.ReadList<Bullet>();
        }

        /// <summary>
        /// Save the game screen into the screen.
        /// </summary>
        /// <param name="writer">The writer.</param>
        public override void Write(BinaryWriter writer)
        {
            base.Write(writer);

            writer.WriteObject(spaceship);
            writer.WriteList(rocks);
            writer.WriteList(bullets);            
        }
    }
}